var app = {
    canvas:null,
    ctx:null,
    bufferCanvas:null,
    bufferCtx:null,
    rowNum:17,
    columnNum:31,
    gridSize:null,
    width:null,
    height:null,
    pos:{x:0,y:0},
    speed:{x:0,y:0},
    watchID:null,
    fps:4,
    meSpirit:null,
    map:null,
    debugArea:null,
    lastDirection:-1,
    RIGHT:0,
    LEFT:1,
    DOWN:2,
    UP:3,
    rightMinAcc:2,
    leftMinAcc:-2,
    downMinAcc:2,
    upMinAcc:1,
    rightCurAcc:null,
    leftCurAcc:null,
    downCurAcc:null,
    upCurAcc:null,
    visualRadius:3,
    init: function(canvasId){
        this.debugArea = document.querySelector('#debugArea');
        this.canvas = this.getDOM(canvasId);
        if(!this.canvas){
            console.log(canvasId+' not found');
            return;
        }
        this.canvas.style.position = 'absolute';
        this.ctx = this.canvas.getContext('2d');
        this.bufferCanvas = document.createElement('canvas');
        this.bufferCtx = this.bufferCanvas.getContext('2d');
        if(!this.ctx){
            console.log(canvasId+' is not a canvas dom');
            return;
        }
        this.resize();
        this.bindEvent();
        this.meSpirit = new Image();
        this.meSpirit.onload = function(){
            app.generateMap();
        };
        this.meSpirit.src = 'img/me.jpg';
    },
    generateMap:function(){
        Maze.extend_algorithm(Maze.AnaHori);
        var config = new Maze.Config();
        config.height = this.rowNum;
        config.width = this.columnNum;
        try {
            var result = Maze.generate(Maze.AnaHori, config);
            this.map = result.data;
            this.start();
        } catch (err) {
            alert('error here:'+err);
        }
    },
    bindEvent:function(){
        if(typeof(Quo) != "undefined"){
            Quo(this.canvas).swipeLeft(function(){
                app.moveLeft();
            });
            Quo(this.canvas).swipeRight(function(){
                app.moveRight();
            });
            Quo(this.canvas).swipeUp(function(){
                app.moveUp();
            });
            Quo(this.canvas).swipeDown(function(){
                app.moveDown();
            });
        }
        else{
            document.onkeydown = function(e){
                switch(e.keyCode){
                    case 37:app.moveLeft();break;
                    case 38:app.moveUp();break;
                    case 39:app.moveRight();break;
                    case 40:app.moveDown();break;
                }
            }
        }
    },
    isEmpty:function(x,y){
        return (x>0)&&(x<this.columnNum-1)&&(y>0)&&(y<this.rowNum-1)&&(this.map[y][x]==1);
    },
    moveLeft:function(){
        var newX = this.pos.x-1;
        var newY = this.pos.y;
        if(this.isEmpty(newX,newY)){
            this.pos.x = newX;
            this.pos.y = newY;
            this.drawMap();
        }
    },
    moveRight:function(){
        var newX = this.pos.x+1;
        var newY = this.pos.y;
        if(this.isEmpty(newX,newY)){
            this.pos.x = newX;
            this.pos.y = newY;
            this.drawMap();
        }
    },
    moveUp:function(){
        var newX = this.pos.x;
        var newY = this.pos.y-1;
        if(this.isEmpty(newX,newY)){
            this.pos.x = newX;
            this.pos.y = newY;
            this.drawMap();
        }
    },
    moveDown:function(){
        var newX = this.pos.x;
        var newY = this.pos.y+1;
        if(this.isEmpty(newX,newY)){
            this.pos.x = newX;
            this.pos.y = newY;
            this.drawMap();
        }
    },
    drawMap:function(){
        this.bufferCtx.fillStyle = '#000';
        this.bufferCtx.fillRect(0,0,this.canvas.width,this.canvas.height);
        var startX = Math.max(0,this.pos.x-this.visualRadius);
        var endX = Math.min(this.columnNum,this.pos.x+this.visualRadius);
        var startY = Math.max(0,this.pos.y-this.visualRadius);
        var endY = Math.min(this.rowNum,this.pos.y+this.visualRadius);
        for(var i = startY; i < endY; i++){
            var array = this.map[i];
            if(!array){
                alert('map error,less row');
                return;
            }
            for(var j = startX; j < endX; j++){
                var flag = array[j];
                switch(flag){
                    case 0:this.bufferCtx.fillStyle = '#333';break;
                    case 1:this.bufferCtx.fillStyle = '#fff';break;
                    default:alert('map error, invalid flag:'+flag);return;
                }
                this.bufferCtx.fillRect(j*this.gridSize,i*this.gridSize,this.gridSize,this.gridSize);
            }
        }
        this.bufferCtx.drawImage(this.meSpirit,this.pos.x*this.gridSize,this.pos.y*this.gridSize,this.gridSize,this.gridSize);
        this.ctx.drawImage(this.bufferCanvas,0,0);
    },
    start:function(){
        this.pos.x = 1;
        this.pos.y = 1;
        this.drawMap();
        // var options = { frequency: 1000/this.fps};
        // this.watchID = navigator.accelerometer.watchAcceleration(function(a){
        //     app.onAcceleration(a)
        // }, function(){
        //     alert('watchAcceleration error');
        // }, options);
    },
    debug:function(str){
        this.debugArea.innerHTML = str;
    },
    onAcceleration:function(acceleration){
        this.drawMap();
        var ax = acceleration.y;
        var ay = acceleration.x;
        var maxAcc = 9.5;
        switch(this.lastDirection){
            case this.RIGHT:
            this.rightCurAcc = Math.min(this.rightCurAcc+0.5,maxAcc);
            this.leftCurAcc = Math.min(this.leftCurAcc+0.5,this.leftMinAcc);
            this.upCurAcc = this.upMinAcc;
            this.downCurAcc = this.downMinAcc;
            break;
            case this.LEFT:
            this.rightCurAcc = Math.max(this.rightCurAcc-0.5,this.rightMinAcc);
            this.leftCurAcc = Math.max(this.leftCurAcc-0.5,-maxAcc);
            this.upCurAcc = this.upMinAcc;
            this.downCurAcc = this.downMinAcc;
            break;
            case this.DOWN:
            this.rightCurAcc = this.rightMinAcc;
            this.leftCurAcc = this.leftMinAcc;
            this.upCurAcc = Math.min(this.upCurAcc+0.5,this.upMinAcc);
            this.downCurAcc = Math.min(this.downCurAcc+0.5,maxAcc);
            break;
            case this.UP:
            this.rightCurAcc = this.rightMinAcc;
            this.leftCurAcc = this.leftMinAcc;
            this.upCurAcc = Math.max(this.upCurAcc-0.5,-maxAcc);
            this.downCurAcc = Math.max(this.downCurAcc-0.5,this.downMinAcc);
            break;
            default:
            this.rightCurAcc = this.rightMinAcc;
            this.leftCurAcc = this.leftMinAcc;
            this.downCurAcc = this.downMinAcc;
            this.upCurAcc = this.upMinAcc;
            break;
        }
        var newX = this.pos.x;
        var newY = this.pos.y;
        if(ax > this.rightCurAcc){
            newX++;
            this.lastDirection = this.RIGHT;
        }
        else if(ax < this.leftCurAcc){
            newX--;
            this.lastDirection = this.LEFT;
        }
        else if(ay > this.downCurAcc){
            newY++;
            this.lastDirection = this.DOWN;
        }
        else if(ay < this.upCurAcc){
            newY--;
            this.lastDirection = this.UP;
        }
        else{
            this.lastDirection = -1;
        }
        if(newX>0&&newX<this.columnNum-1&&newY>0&&newY<this.rowNum-1&&this.map[newY][newX]==1){
            this.pos.x = newX;
            this.pos.y = newY;
        }
    },
    resize:function(){
        this.width = window.innerWidth;
        this.height = window.innerHeight;
        document.body.style.width = this.width+'px';
        document.body.style.height = this.height+'px';
        this.gridSize = Math.min(this.width/this.columnNum,this.height/this.rowNum).toFixed(2);
        this.bufferCanvas.width = this.canvas.width = this.gridSize*this.columnNum;
        this.bufferCanvas.height = this.canvas.height = this.gridSize*this.rowNum;
        this.canvas.style.width = this.canvas.width+'px';
        this.canvas.style.height = this.canvas.height+'px';
        var toTop = (this.height-this.canvas.height)/2+'px';
        var toLeft = (this.width-this.canvas.width)/2+'px';
        this.canvas.style.left = toLeft;
        this.canvas.style.top = toTop;
    },
    getDOM:function(id){
        return document.querySelector('#'+id);
    }
};
